/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */

#include "M2Model.h"

#include "M2ModelInfo.h"
#include "M2AnimData.h"

#include "ChrHairGeoDbc.h"
#include "AnimDataDbc.h"

#include "CharacterModelArchive.h"

namespace PQGame
{
	M2Model::ModelMap M2Model::_list;
	M2Model::M2Model(std::string path)
		: _path(path),_hairIndex(-1)
	{
		initModelFiles();
		initSubMeshes();
		initAnims();
	}

	M2Model::~M2Model()
	{
		if(_materialLoader){
			delete _materialLoader;
			_materialLoader=0;
		}
	}

	void M2Model::initModelFiles()
	{
		_m2File=SCharacterModelArchive.openM2File(_path);
		if(!_m2File||!_m2File->ok()){
			return;
		}

		_skinFile=SCharacterModelArchive.openM2SkinFile(_m2File->getSkinFileName());
		if(!_skinFile||!_skinFile->ok()){
			return;
		}

		_boneCount=_m2File->getBoneCount();

	}


	void M2Model::initSubMeshes()
	{
		_m2SubMeshCount=_skinFile->getSubMeshCount();
		_m2TexUnits=_skinFile->getTexUnitPtr();
		_m2SubMeshes=_skinFile->getSubMeshPtr();
		_m2Indices=_skinFile->getIndicesPtr();
		_m2Vertices=_m2File->getVerticesPtr();
		_modelInfo=M2ModelInfo::get(_m2File);

		for (int i=0; i<_m2SubMeshCount; i++) {
			M2ModelSubMesh submesh;
			submesh.show = (_m2SubMeshes[i].id==0);
			
			_subMeshes.push_back(submesh);
		}

		_materialLoader=new M2MaterialLoader("General",_m2File);
		_bodyMatName=_materialLoader->loadBodyMaterial();
		_hairMatName=_materialLoader->loadHairMaterial();

		if(_modelInfo->isCharacter()){
			initCharSubMeshes();
		}
	}


	void M2Model::initCharSubMeshes()
	{
		for (int i=0; i<_m2SubMeshCount; i++) {
			_subMeshes[i].materialName=_bodyMatName;
		}

		CharDetails& detail= _modelInfo->getCharDetail();
		
		chooseHair(detail.hairStyle);
		
		// reset model _m2SubMeshes
		for (int i=0;i<_m2SubMeshCount; i++) {
			//_showSubMeshes[i]=true;
			int id=_m2SubMeshes[i].id;
			if (id == 1){
				_subMeshes[i].show = false;//bald
			}

			for (int j=1; j<16; j++) {
				int a = j*100, b = (j+1) * 100;
				if (id>a && id<b) {
					_subMeshes[i].show =(id==(a+detail.submeshes[j]));
				}
			}
		}
	}

	void M2Model::chooseHair(int hairStyle)
	{
		if(_hairIndex>=0){
			_subMeshes[_hairIndex].show=false;//hide last
			_subMeshes[_hairIndex].materialName=_bodyMatName;//??
		}

		CharDetails& detail= _modelInfo->getCharDetail();
		detail.hairStyle=hairStyle;
		std::vector<CharHairGeoRecord*> list=GNgChrHairGeoDbc.getRecords(detail.race,detail.gender);
		int size=list.size();
		for(int i=0;i<size;i++){
			CharHairGeoRecord *record= list[i];
			if (record!=0&&record->geoset!=0) {
				for (int j=0; j<_m2SubMeshCount; j++) {
					if (_m2SubMeshes[j].id== record->geoset) {//find submesh(geoset) id equ
						_subMeshes[j].show =(hairStyle==record->hairstyle);//(cd.hairStyle == section) && showHair;
						if(_subMeshes[j].show){
							_subMeshes[j].type=M2_SUB_TYPE_HAIR;
							_subMeshes[j].materialName=_bodyMatName;
							_hairIndex=j;
						}
					}
				}
			}else{
			}
		}
	}

	void M2Model::initAnims()
	{
		_animCount=_m2File->getAnimCount();
		_m2Anims=_m2File->getAnimsPtr();
		
		std::string path = _path.substr(0, _path.length()-3);
		char name[256];

		for(int i=0;i<_animCount;i++){
			int animId=_m2File->getAnimId(i);
			int subAnimId=_m2File->getSubAnimId(i);
			sprintf(name, "%s%04d-%02d.anim", path.c_str(), animId, subAnimId);
			M2AnimFile* p=SCharacterModelArchive.openM2AnimFile(name);
			_animFileList.push_back(p);//p==0 is push too

			ChrAnimDataRecord* record=GNgAnimDataDbc.getRecord(animId);
			std::string name="";
			if(record){
				name=GNgAnimDataDbc.getString(record->name);
				name+="["+Ogre::StringConverter::toString(i);
				name+="]";
			}
			_animNameList.push_back(name);
		}

		initBoneAnimData();

	}

	void M2Model::initBoneAnimData()
	{
		M2Bone* bones= _m2File->getBonePtr();
		for(int b=0;b<_boneCount;b++){
			M2AnimData* dtTr= new M2AnimData(this,bones[b].translation);
			M2AnimData* dtRt= new M2AnimData(this,bones[b].rotation);
			M2AnimData* dtSc= new M2AnimData(this,bones[b].scaling);
			_boneTranslateAnims.push_back(dtTr);
			_boneRotateAnims.push_back(dtRt);
			_boneScaleAnims.push_back(dtSc);
		}
	}


}
